package dict

import (
	"playbook/ginsvr/src/global"
	"playbook/ginsvr/src/orm"
	"playbook/ginsvr/src/source/gene"
	"playbook/ginsvr/src/utils/fileutil"
	"playbook/ginsvr/src/utils/uuidutil"
	"strings"

	"github.com/sirupsen/logrus"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

var db *gorm.DB
var err error

func init() {
	db, err = gorm.Open(sqlite.Open("playbook.db"), &gorm.Config{Logger: logger.Default.LogMode(logger.Info)})
}

//按条件查询字典表，并分页
func GetParamByCondiction(param map[string]interface{}) map[string]interface{} {
	params := []map[string]interface{}{}
	tx := db.Table("paramdefine")
	//拼接查询条件
	if nil != param["name"] && "" != param["name"] {
		tx = tx.Where("name like ?", "%"+param["name"].(string)+"%")
	}
	if nil != param["type"] && "" != param["type"] {
		tx = tx.Where("type = ?", param["type"])
	}
	if nil != param["classPath"] && "" != param["classPath"] {
		tx = tx.Where("classpath like ?", "%"+param["classPath"].(string)+"%")
	}
	if nil != param["desc"] && "" != param["desc"] {
		tx = tx.Where("desc like ?", "%"+param["desc"].(string)+"%")
	}
	pageNum := 1
	pageSize := 1
	if param["ispage"] == "1" {
		pageNum = int(param["pageNum"].(float64))
		pageSize = int(param["pageSize"].(float64))
	}

	var count int64 = 0

	//查询总条数
	result := tx.Count(&count)
	if nil != result.Error {
		global.LOG.WithFields(logrus.Fields{
			"err": result.Error,
		}).Error("get parameters by condition err,get data err, get count err.")

		return map[string]interface{}{
			"respCode": "000001",
			"respMsg":  result.Error.Error(),
			"data":     "",
		}
	}
	if param["ispage"] == "1" {
		//分页查询数据
		result = tx.Limit(pageSize).Offset((pageNum - 1) * pageSize).Find(&params)
	} else {
		result = tx.Find(&params)
	}

	if nil != result.Error {
		global.LOG.WithFields(logrus.Fields{
			"err": result.Error,
		}).Error("get parameters by condition err,get data err.")

		return map[string]interface{}{
			"respCode": "000001",
			"respMsg":  result.Error.Error(),
			"data":     "",
		}
	}
	//构造返回参数
	return map[string]interface{}{
		"respCode": "000000",
		"respMsg":  "查询成功",
		"data": map[string]interface{}{
			"data":     params,
			"total":    count,
			"pageNum":  pageNum,
			"pageSize": pageSize,
		},
	}
}

//获取字典表中所有参数
func GetAllParams() map[string]interface{} {
	//	var response Response
	params := []map[string]interface{}{}
	result := db.Table("paramdefine").Find(&params)
	if nil != result.Error {
		global.LOG.WithFields(logrus.Fields{
			"err": result.Error,
		}).Error("get all parameters err.")

		return map[string]interface{}{
			"respCode": "000001",
			"respMsg":  result.Error.Error(),
			"data":     "",
		}
	}
	return map[string]interface{}{
		"respCode": "000000",
		"respMsg":  "",
		"data":     params,
	}
}

//数据字典中新增参数
func AddParamInDict(param map[string]interface{}) map[string]interface{} {

	//res := map[string]interface{}{}
	name := param["name"].(string)

	_, count := getParamDefineByName(name)

	if count > 0 {
		return map[string]interface{}{
			"respCode": "000001",
			"respMsg":  "新增失败，数据字典中存在同名参数",
		}
	}
	return addParamInDict(param)
}

func addParamInDict(param map[string]interface{}) map[string]interface{} {
	paramdefMap := map[string]map[string]interface{}{}
	idMap := map[string]string{}
	relas := []orm.Paramrelation{}
	res := addParamDefine(param, paramdefMap, idMap, &relas)
	if "000000" != res["respCode"] {
		return res
	}
	//新增参数
	err := saveParamDefinesByMap(paramdefMap)
	if nil != err {
		return map[string]interface{}{
			"respCode": "000001",
			"respMsg":  "新增失败," + err.Error(),
		}
	}
	//新增关联关系
	err = orm.SaveParamRelas(relas)
	if nil != err {
		return map[string]interface{}{
			"respCode": "000001",
			"respMsg":  "新增失败," + err.Error(),
		}
	}
	//生成DTO类
	err = geneAllDTO(idMap)
	if nil != err {
		return map[string]interface{}{
			"respCode": "000001",
			"respMsg":  "新增失败," + err.Error(),
		}
	}
	return map[string]interface{}{
		"respCode":    "000000",
		"respMsg":     "新增成功",
		"parameterid": res["parameterid"],
	}
}

//生成map中[id, classpath]所有参数的java类
func geneAllDTO(idMap map[string]string) error {

	for k, v := range idMap {
		strarr := strings.Split(v, ".")
		clasname := "." + strarr[len(strarr)-1]
		claspath := strings.Replace(v, clasname, "", -1)
		claspath = strings.Replace(claspath, ".", global.PTHSEP, -1)
		gene.GeneDictParamBean("dictbean", k, claspath)

	}
	return nil
}

//批量保存参数定义
func saveParamDefinesByMap(paramdefMap map[string]map[string]interface{}) error {
	paramdefs := []map[string]interface{}{}
	if len(paramdefMap) > 0 {
		for _, param := range paramdefMap {
			paramdefs = append(paramdefs, param)
		}
	}
	err := orm.SaveParamDefines(paramdefs)
	return err
}

//字典表中添加参数
func addParamDefine(parameter map[string]interface{}, paramdefMap map[string]map[string]interface{},
	ids map[string]string, relas *[]orm.Paramrelation) map[string]interface{} {

	name := parameter["name"]
	classpath := parameter["classPath"]
	parametertype := parameter["type"]
	desc := parameter["desc"]
	if parametertype == "Map" && classpath != nil {
		strarr := strings.Split(classpath.(string), ".")
		name = strarr[len(strarr)-1]
	}

	//如果是字典中已有的参数，返回ID
	pp, count := getParamDefineByName(name.(string))
	if count > 0 {
		return map[string]interface{}{
			"respCode":    "000000",
			"respMsg":     "",
			"parameterid": pp["parameterid"],
		}
	}
	paramid := uuidutil.GetUUID()
	paramdefMap[name.(string)] = map[string]interface{}{
		"parameterid": paramid,
		"name":        name,
		"classpath":   classpath,
		"type":        parametertype,
		"desc":        desc,
	}
	//如果是List类型，添加内层泛型
	if "List" == parametertype {
		//如果没有定义泛型,返回错误信息
		if parameter["parameter"] == nil || len(parameter["parameter"].([]interface{})) == 0 {
			return map[string]interface{}{
				"respCode": "000001",
				"respMsg":  "新增失败,List中泛型信息不完整",
			}
		}
		//取得内层泛型定义
		subparam := parameter["parameter"].([]interface{})[0].(map[string]interface{})
		if _, ok := subparam["type"]; !ok {
			return map[string]interface{}{
				"respCode": "000001",
				"respMsg":  "新增失败,List中泛型信息不完整",
			}
		}
		elementype := subparam["type"]
		//如果是DTO,添加该参数
		if elementype == "Map" {
			subparamid := addParamDefine(subparam, paramdefMap, ids, relas)
			addParamRel(paramid, subparamid["parameterid"].(string), "lst", "1", "", relas)
		} else {
			subparamid := subparam["type"]
			addParamRel(paramid, subparamid.(string), "lst", "0", "", relas)
		}
	} else if "Map" == parametertype {
		//如果是DTO类型:
		//	1.添加属性参数和Relation
		//	2.生成参数的定义类
		paramInList := parameter["parameter"].([]interface{})
		for _, subp := range paramInList {
			subparam := subp.(map[string]interface{})
			subparamid := addParamDefine(subparam, paramdefMap, ids, relas)
			//新增parameter层级关系
			if (subparam["type"]) == "Map" {
				addParamRel(paramid, subparamid["parameterid"].(string), "sub", "1", subparam["name"].(string), relas)
			} else {
				addParamRel(paramid, subparamid["parameterid"].(string), "sub", "0", "", relas)
			}
		}
		//将id添加进idMap中
		ids[paramid] = classpath.(string)
	}

	return map[string]interface{}{
		"respCode":    "000000",
		"respMsg":     "",
		"parameterid": paramid,
	}
}

//根据名称查询字典表中记录，返回一条数据
func getParamDefineByName(name string) (param map[string]interface{}, count int64) {

	db.Table("paramdefine").Where("name = ?", name).Find(&param).Count(&count)
	return param, count
}

func getParamDefineByName2(name string, db *gorm.DB) (param map[string]interface{}, count int64) {

	db.Table("paramdefine").Where("name = ?", name).Find(&param).Count(&count)
	return param, count
}

//根据名称查询字典表中记录，返回一条数据
func GetParamDefineByName(name string) (param map[string]interface{}, count int64) {

	return getParamDefineByName(name)
}

//批量添加关联关系
func addParamRel(parentparamid string, subparamid string, reltype string, isbasetype string, relname string,
	relas *[]orm.Paramrelation) {
	*relas = append(*relas, orm.Paramrelation{
		Parentparamid: parentparamid,
		Subparamid:    subparamid,
		Reltype:       reltype,
		Isbasetype:    isbasetype,
		Relname:       relname,
	})
}

//根据ID查询字典表参数信息，包含子参数
func GetParamdefById(paramid string, relname string) map[string]interface{} {

	param := getParamDefById(paramid)
	var paramMap = make(map[string]interface{})
	if relname == "" {
		paramMap["name"] = param.Name
	} else {
		paramMap["name"] = relname
	}
	paramMap["classPath"] = param.Classpath
	paramMap["type"] = param.Type
	paramMap["parameterid"] = param.Parameterid

	if param.Type == "Map" {
		if relname == "" {
			strarr := strings.Split(param.Classpath, ".")
			paramMap["mappingname"] = strarr[len(strarr)-1]
		} else {
			paramMap["mappingname"] = relname
		}

	} else if param.Type == "List" {
		paramMap["mappingname"] = paramMap["name"].(string) + "[]"
	} else {
		paramMap["mappingname"] = paramMap["name"]
	}

	var paramrel []orm.Paramrelation
	var count int64
	db.Table("paramrelation").Where("parentparamid = ?", paramid).Find(&paramrel).Count(&count)

	if count == 0 {
		return paramMap
	}

	if param.Type == "List" {
		//list中元素为基本类型或子parameter，不允许使用javaMap(HashMap)
		var paramrs []map[string]interface{}
		pl := paramrel[0]
		//如果元素为parameter，对子参数进行递归遍历
		if len([]rune(pl.Subparamid)) == 32 {
			paramrsubs := GetParamdefById(pl.Subparamid, pl.Relname)
			paramrs = append(paramrs, paramrsubs)
			paramMap["parameter"] = paramrs
		} else {
			//如果子参数是基本类型，只需要新增一次
			var paramtemp = make(map[string]interface{})
			paramtemp["type"] = pl.Subparamid
			paramtemp["mappingname"] = pl.Subparamid
			paramtemp["name"] = param.Name + pl.Subparamid
			paramrs = append(paramrs, paramtemp)
			paramMap["parameter"] = paramrs

		}
	} else if param.Type == "Map" {
		var paramrs []map[string]interface{}
		for _, pl := range paramrel {
			if pl.Reltype == "sub" {
				paramrsubs := GetParamdefById(pl.Subparamid, pl.Relname)
				paramrs = append(paramrs, paramrsubs)
			}
		}
		paramMap["parameter"] = paramrs
	}

	return paramMap
}

func getParamDefById(paramid string) (param orm.Parameter) {
	db.Table("paramdefine").Where("parameterid = ?", paramid).Find(&param)
	return param
}

//更新字典中参数信息
func UpdateParamdef(param map[string]interface{}) map[string]interface{} {
	name := param["name"]
	classpath := param["classPath"]
	parametertype := param["type"]
	desc := param["desc"]
	paramid := param["parameterid"].(string)

	//如果是map, 将classpath中的name替换成接收到的name
	if parametertype == "Map" && classpath != nil {
		strarr := strings.Split(classpath.(string), ".")
		strarr[len(strarr)-1] = name.(string)
		classpath = strings.Join(strarr, ".")
	}

	if parametertype == "List" && (param["parameter"] == nil || len(param["parameter"].([]interface{})) == 0) {
		return map[string]interface{}{
			"respCode": "000001",
			"respMsg":  "字典表更新失败，List中泛型不能为空",
		}
	}
	//根据id拿到旧数据
	oldData := getParamDefById(paramid)

	//更新字典表
	err := db.Table("paramdefine").Where("parameterid = ?", paramid).Updates(map[string]interface{}{
		"name":      name,
		"type":      parametertype,
		"classpath": classpath,
		"desc":      desc,
	}).Error
	if nil != err {
		global.LOG.WithFields(logrus.Fields{
			"err": err,
		}).Error("update table paramdefine err.")
		return map[string]interface{}{
			"respCode": "000001",
			"respMsg":  "字典表更新失败",
		}
	}

	//删除关联关系
	orm.DeleteParamRel(paramid)

	//如果是基础数据类型，结束
	if _, ok := param["parameter"]; !ok {
		return map[string]interface{}{
			"respCode": "000000",
			"respMsg":  "",
		}
	}

	relas := []orm.Paramrelation{}

	//如果是List或Map，新增关联关系
	if "List" == parametertype {

		subparam := param["parameter"].([]interface{})[0].(map[string]interface{})

		elementype := subparam["type"]
		//如果是DTO,添加该参数
		if elementype == "Map" {
			subparamid := addParamInDict(subparam)["parameterid"]
			addParamRel(paramid, subparamid.(string), "lst", "1", "", &relas)
		} else {
			subparamid := subparam["type"]
			addParamRel(paramid, subparamid.(string), "lst", "0", "", &relas)
		}
	} else if "Map" == parametertype {
		//如果是DTO类型:
		//	1.添加属性参数和Relation
		//	2.生成参数的定义类
		paramInList := param["parameter"].([]interface{})
		for _, subp := range paramInList {
			subparam := subp.(map[string]interface{})
			subparamid := addParamInDict(subparam)
			//新增parameter层级关系
			if (subparam["type"]) == "Map" {
				addParamRel(paramid, subparamid["parameterid"].(string), "sub", "1", subparam["name"].(string), &relas)
			} else {
				addParamRel(paramid, subparamid["parameterid"].(string), "sub", "0", "", &relas)
			}
		}

	}
	//新增关联关系
	err = orm.SaveParamRelas(relas)
	if nil != err {
		return map[string]interface{}{
			"respCode": "000001",
			"respMsg":  "更新失败,保存关联关系失败：" + err.Error(),
		}
	}
	if "Map" == parametertype {
		//删除原DTO类
		oldpath := oldData.Classpath
		oldpath = strings.Replace(oldpath, ".", global.PTHSEP, -1) + ".java"
		head := orm.GetGeneSrcDefine("dictbean").Srcpath
		oldpath = head + global.PTHSEP + oldpath
		fileutil.DeleteFile(oldpath, false)

		//生成DTO类
		idMap := map[string]string{}
		idMap[paramid] = classpath.(string)
		err = geneAllDTO(idMap)
		if nil != err {
			return map[string]interface{}{
				"respCode": "000001",
				"respMsg":  "更新失败,生成java类失败" + err.Error(),
			}
		}
	}

	return map[string]interface{}{
		"respCode": "000000",
		"respMsg":  "更新成功",
	}

}

//删除字典中的参数信息
func DeleteParamdefById(paramid string) map[string]interface{} {

	relas, count := getRelas(paramid)
	if count > 0 {
		params := []orm.Parameter{}
		for _, rela := range relas {
			pp := getParamDefById(rela.Parentparamid)
			params = append(params, pp)
		}
		return map[string]interface{}{
			"respCode":  "000001",
			"respMsg":   "参数已被其他参数引用，无法删除",
			"usedParam": params,
		}
	}
	//删除关联关系
	orm.DeleteParamRel(paramid)

	//删除字典表数据
	err := delParamDefById(paramid)
	if err != nil {
		return map[string]interface{}{
			"respCode": "000001",
			"respMsg":  "删除字典表失败" + err.Error(),
		}
	}
	return map[string]interface{}{
		"respCode": "000000",
		"respMsg":  "删除成功",
	}
}

func getRelas(paramid string) (relas []orm.Paramrelation, count int64) {

	db.Table("paramrelation").Where("subparamid=?  ", paramid).Find(&relas).Count(&count)
	return relas, count
}

func delParamDefById(paramid string) error {
	err := db.Exec("delete from paramdefine  where parameterid=$1", paramid).Error
	if err != nil {
		global.LOG.WithFields(logrus.Fields{
			"err": err,
		}).Error("delete data in paramdefine err.")
	}
	return err
}

func UpdDict(param map[string]interface{}) string {
	pold, count := getParamDefineByName(param["name"].(string))
	delete(param, "optional")
	if count == 0 {
		param["parameterid"] = uuidutil.GetUUID()

		db.Table("paramdefine").CreateInBatches(param, 1)
		return param["parameterid"].(string)
	} else {
		db.Table("paramdefine").Where("parameterid = ?", pold["parameterid"]).Updates(param)
		return pold["parameterid"].(string)
	}
}

func updDict(param map[string]interface{}, db *gorm.DB) string {
	pold, count := getParamDefineByName2(param["name"].(string), db)
	delete(param, "optional")
	if count == 0 {
		param["parameterid"] = uuidutil.GetUUID()

		db.Table("paramdefine").CreateInBatches(param, 1)
		return param["parameterid"].(string)
	} else {
		db.Table("paramdefine").Where("parameterid = ?", pold["parameterid"]).Updates(param)
		return pold["parameterid"].(string)
	}
}

func BatchUpdate(params []*map[string]interface{}) error {
	tx := db.Begin()
	for _, param := range params {
		id := updDict(*param, tx)
		pp := *param
		pp["parameterid"] = id
	}
	tx.Commit()
	return nil
}

func GetParamDefTreeByName(name string) map[string]interface{} {
	paramid := ""
	db.Table("paramdefine").Select("parameterid").Where("name = ?", name).Find(&paramid)

	return GetParamdefById(paramid, "")
}
